package Work;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;

import moodish.comm.ClientSideMessage;
import moodish.comm.ServerComm;
import moodish.comm.ServerSideMessage;

public class ServerSide implements ServerComm, Runnable {
	public static final int PORT = 8082;
	LinkedList<Connections> connectedlist = new LinkedList<Connections>();
	
	ServerSocket socketServer;
	
	LinkedList<ServerMessage> incomingMsgServerList = new LinkedList<ServerMessage>();

	


	@Override
	public void start() {
		try {
			
			socketServer = new ServerSocket(PORT);

			
			Thread thisThread = new Thread(this);
			thisThread.start();

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
/***
 * Runnning Thread that accepts connections from clients;
 */
	public void run() {

		try {
			try {
				while (!socketServer.isClosed()) {
					Socket socketclient = socketServer.accept();
					Connections connected = new Connections(socketclient, this);
					connectedlist.add(connected);
					connected.start();
				}

			} finally {
				socketServer.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public ServerSideMessage getNextMessage() {
		ServerMessage msg;
		synchronized (incomingMsgServerList) {

			while (hasNextMessage() == false) {
				try {
					incomingMsgServerList.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			msg = (ServerMessage) incomingMsgServerList.poll();
		}
		return msg;
	}

	@Override
	public boolean hasNextMessage() {
		if (!incomingMsgServerList.isEmpty()) {
			return true;
		}
		return false;
	}

	@Override
	public void sendMoodishMessage(String fromNicename, String toNickname,
			String moodishMessage) {
		ClientMessage msg = new ClientMessage(
				ClientSideMessage.Type.MOODISH_MESSAGE, fromNicename,
				moodishMessage);
		send(msg, toNickname);
	}

	@Override
	public void sendNewFriendship(String toNickname, String newFriendship) {
		ClientMessage msg = new ClientMessage(
				ClientSideMessage.Type.FRIENDSHIP, ClientSideMessage.SERVER,
				newFriendship);
		send(msg, toNickname);
	}

	@Override
	public void sendNewUnfriendship(String toNickname, String unfriendship) {
		ClientMessage msg = new ClientMessage(
				ClientSideMessage.Type.UNFRIENDSHIP, ClientSideMessage.SERVER,
				unfriendship);
		send(msg, toNickname);
	}

	@Override
	public void sendError(String toNickname, String error) {
		ClientMessage msg = new ClientMessage(ClientSideMessage.Type.ERROR,
				ClientSideMessage.SERVER, error);
		send(msg, toNickname);
	}

	@Override
	public void sendClientConnected(String toNickname, String connectedNickname) {
		ClientMessage msg = new ClientMessage(ClientSideMessage.Type.CONNECTED,
				ClientSideMessage.SERVER, connectedNickname);
		send(msg, toNickname);
	}

	@Override
	public void sendClientDisconnected(String toNickname,
			String disconnectedNickname) {
		ClientMessage msg = new ClientMessage(
				ClientSideMessage.Type.DISCONNECTED, ClientSideMessage.SERVER,
				disconnectedNickname);
		send(msg, toNickname);
	}

	@Override
	public boolean clientIsConnected(String nickname) {
		for (Connections connection : connectedlist) {
			if (connection.getNickname().equals(nickname)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public void disconnectClient(String nickname) {
		for (int i = 0; i < connectedlist.size(); i++) {
			String connecionNickname = connectedlist.get(i).getNickname();

			if (connecionNickname != null && connecionNickname.equals(nickname)) {
				sendClientDisconnected(nickname, nickname);
				connectedlist.get(i).disconnect();
				connectedlist.remove(connectedlist.get(i));
				break;
			}
		}
	}

	/***
	 * This method receives a message of the type Client and sends it to received ninkname; 
	 */
	public void send(ClientMessage msg, String toNickname) {
		ToSerialize msgSerialized = new ToSerialize(msg);

		for (int i = 0; i < connectedlist.size(); i++) {
			String connecionNickname = connectedlist.get(i).getNickname();

			if (connecionNickname != null
					&& connecionNickname.equals(toNickname)) {
				connectedlist.get(i).send(msgSerialized);
			}
		}

	}

	/***
	 * This method adds a message of the type Server to the List;
	 */
	public synchronized void addMessage(ServerMessage sm) {
		synchronized (incomingMsgServerList) {
			incomingMsgServerList.add(sm);
			incomingMsgServerList.notify();
		}	
	}
/***
 * Test Method - Not Used; Disconncts the clients and shutdown;
 */
	public void shutDown() {
		for (int i = 0; i < connectedlist.size(); i++) {
			connectedlist.get(i).disconnect();
		}
		System.exit(0);
	}

}